//
//  BYWebView.m
//  Unity-iPhone
//
//  Created by 胡忠诚 on 2018/4/26.
//通用的WebView

#import "BYWebView.h"
#import "BYWebViewProgress.h"//webView的进度条
#import <TargetConditionals.h>
#import <dlfcn.h>
#import <WebKit/WebKit.h>

#define BY_kWeakSelf(weakSelf) __weak __typeof(&*self) weakSelf = self;
@interface BYWebView()<UIWebViewDelegate,WKNavigationDelegate,WKUIDelegate,BYWebViewProgressDelegate>
/**加载进度的值（WK、UI)*/
@property (nonatomic, assign) double progressValue;
/**webView加载进度的值*/
@property (nonatomic, strong) BYWebViewProgress* webViewProgress;
/**进度条的View（WK、UI)*/
@property (nonatomic, strong)UIView *progressView;
/**原始的请求*/
@property (nonatomic, strong) NSURLRequest *originRequest;
/**当前的请求*/
@property (nonatomic, strong) NSURLRequest *currentRequest;

@end
@implementation BYWebView
@synthesize usingUIWebView = _usingUIWebView;
@synthesize realWebView = _realWebView;
@synthesize scalesPageToFit = _scalesPageToFit;
#pragma mark- init初始化
- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self initAddSubViews];
    }
    return self;
}
- (void)initAddSubViews{
    self.backgroundColor = [UIColor whiteColor];
    //web页cookie的处理:这里统一用UIWebView吧
//    Class wkWebView = NSClassFromString(@"WKWebView");
//    if(wkWebView){//使用WKWebView
//        [self initWKWebView];
//        _usingUIWebView = NO;
//    }else{
        [self initUIWebView];
        _usingUIWebView = YES;
//    }
    self.scalesPageToFit = YES;//是否根据视图大小来缩放页面：默认为YES
    [self.realWebView setFrame:self.bounds];
    [self.realWebView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
    [self addSubview:self.realWebView];
    [self addProgressView];//添加进度条的view
}

#pragma mark- WKWebView专区
- (void)initWKWebView{//初始化
    WKWebViewConfiguration* configuration = [[NSClassFromString(@"WKWebViewConfiguration") alloc] init];
    configuration.preferences = [NSClassFromString(@"WKPreferences") new];
    configuration.userContentController = [NSClassFromString(@"WKUserContentController") new];
    WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.bounds configuration:configuration];
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    webView.backgroundColor = [UIColor clearColor];
    webView.opaque = NO;
    [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    _realWebView = webView;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if([keyPath isEqualToString:@"estimatedProgress"]){//监听WKWebView的加载进度
        self.progressValue = [change[NSKeyValueChangeNewKey] doubleValue];
        [self setProgressViewProgress:self.progressValue animated:YES];
    }else if([keyPath isEqualToString:@"title"]){
        self.title = change[NSKeyValueChangeNewKey];
    }
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{//WKWebView:网页URL和内容变化的时候调用
    BOOL resultBOOL = [self callback_webViewShouldStartLoadWithRequest:navigationAction.request navigationType:navigationAction.navigationType];
    if(resultBOOL){
        self.currentRequest = navigationAction.request;
        if(navigationAction.targetFrame == nil){
            [webView loadRequest:navigationAction.request];
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }else{
        decisionHandler(WKNavigationActionPolicyCancel);
    }
}
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{//WKWebView开始加载
    [self callback_webViewDidStartLoad];
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{//WKWebView加载完成
    [self callback_webViewDidFinishLoad];
}
- (void)webView:(WKWebView *) webView didFailProvisionalNavigation: (WKNavigation *) navigation withError: (NSError *) error{//WKWebView加载失败
    [self callback_webViewDidFailLoadWithError:error];
}
- (void)webView: (WKWebView *)webView didFailNavigation:(WKNavigation *) navigation withError: (NSError *) error{//WKWebView加载失败
    [self callback_webViewDidFailLoadWithError:error];
}

#pragma mark- UIWebView专区
- (void)initUIWebView{
    UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, KSCREEWIDTH, KSCREEHEGIHT)];
    webView.scrollView.bounces = NO;
    webView.backgroundColor = [UIColor clearColor];
    webView.opaque = NO;
    for (UIView *subview in [webView.scrollView subviews]){
        if ([subview isKindOfClass:[UIImageView class]]){
            ((UIImageView *) subview).image = nil;
            subview.backgroundColor = [UIColor clearColor];
        }
    }
    self.backbtn = [UIButton buttonWithType:UIButtonTypeCustom];
    self.backbtn.frame =CGRectMake(KSCREEWIDTH-60,10,30,30);
    [self.backbtn addTarget:self action:@selector(backbtnClick) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:self.backbtn];

    //webView的进度条的值
    self.webViewProgress = [[BYWebViewProgress alloc] init];
    webView.delegate = _webViewProgress;
    _webViewProgress.webViewProxyDelegate = self;
    _webViewProgress.progressDelegate = self;
    _realWebView = webView;
}
- (void)webViewProgress:(BYWebViewProgress *)webViewProgress updateProgress:(float)progress{//UIWebView加载进度的代理方法
    self.progressValue = progress;
    [self setProgressViewProgress:self.progressValue animated:YES];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{//UIWebView:网页URL和内容变化的时候调用
    BOOL resultBOOL = [self callback_webViewShouldStartLoadWithRequest:request navigationType:navigationType];
    return resultBOOL;
}
- (void)webViewDidStartLoad:(UIWebView *)webView{//UIWebView开始加载
    [self callback_webViewDidStartLoad];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{//UIWebView加载完成
    self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    if(self.originRequest == nil){
        self.originRequest = webView.request;
    }
    [self callback_webViewDidFinishLoad];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{//UIWebView加载失败
    [self callback_webViewDidFailLoadWithError:error];
}

#pragma mark- 进度条专区（WK和UIWebView）
- (void)addProgressView{//添加进度条View
    _progressView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 2.0f)];
    _progressView.backgroundColor = [UIColor colorWithRed:22.f / 255.f green:126.f / 255.f blue:251.f / 255.f alpha:1.0];
    _progressView.alpha = 0.0;
    [self addSubview:_progressView];
    [self bringSubviewToFront:_progressView];
}
- (void)setProgressViewProgress:(float)progress animated:(BOOL)animated{//更新进度条View的宽度
    WS(ws);
    BOOL isGrowing = progress > 0.0;
    [UIView animateWithDuration:(isGrowing && animated) ? 0.27f : 0.0 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        CGRect frame = ws.progressView.frame;
        frame.size.width = progress * self.bounds.size.width;
        ws.progressView.frame = frame;
    } completion:nil];
    //控制进度条是否显示
    if (progress >= 1.0) {
        [UIView animateWithDuration:animated ? 0.27f : 0.0 delay:0.1f options:UIViewAnimationOptionCurveEaseInOut animations:^{
            ws.progressView.alpha = 0.0;
        } completion:^(BOOL completed){
            CGRect frame = ws.progressView.frame;
            frame.size.width = 0;
            ws.progressView.frame = frame;
        }];
    }else {
        [UIView animateWithDuration:animated ? 0.27f : 0.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            ws.progressView.alpha = 1.0;
        } completion:nil];
    }
}

#pragma mark- BYWKWebView代理对外部的回调（WK和UIWebView）
- (void)callback_webViewDidFinishLoad{//网页加载完成（WK和UIWebView）
    if([self.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]){
        [self.delegate webViewDidFinishLoad:self];
    }
}
- (void)callback_webViewDidStartLoad{//网页开始加载（WK和UIWebView）
    if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]){
        [self.delegate webViewDidStartLoad:self];
    }
}
- (void)callback_webViewDidFailLoadWithError:(NSError *)error{//网页加载失败（WK和UIWebView）
    if([self.delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]){
        [self.delegate webView:self didFailLoadWithError:error];
    }
}
- (BOOL)callback_webViewShouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(NSInteger)navigationType{//网页URL和内容变化的时候调用（WK和UIWebView）
    BOOL resultBOOL = YES;
    if([self.delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]){
        if(navigationType == -1) {
            navigationType = UIWebViewNavigationTypeOther;
        }
        resultBOOL = [self.delegate webView:self shouldStartLoadWithRequest:request navigationType:navigationType];
    }
    return resultBOOL;
}

#pragma mark- 属性方法
- (NSURLRequest *)currentRequest{//当前的请求
    if(_usingUIWebView){
        return [(UIWebView*)self.realWebView request];;
    }else{
        return _currentRequest;
    }
}
- (void)setScalesPageToFit:(BOOL)scalesPageToFit{//设置是否根据视图大小来缩放页面
    if(_usingUIWebView){
        UIWebView* webView = _realWebView;
        webView.scalesPageToFit = scalesPageToFit;
    }else{
        if(_scalesPageToFit == scalesPageToFit){
            return;
        }
        WKWebView* webView = _realWebView;
        NSString *jScript = @"var meta = document.createElement('meta'); \
        meta.name = 'viewport'; \
        meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'; \
        var head = document.getElementsByTagName('head')[0];\
        head.appendChild(meta);";
        
        if(scalesPageToFit){
            WKUserScript *wkUScript = [[NSClassFromString(@"WKUserScript") alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
            [webView.configuration.userContentController addUserScript:wkUScript];
        }else{
            NSMutableArray* array = [NSMutableArray arrayWithArray:webView.configuration.userContentController.userScripts];
            for (WKUserScript *wkUScript in array){
                if([wkUScript.source isEqual:jScript]){
                    [array removeObject:wkUScript];
                    break;
                }
            }
            for (WKUserScript *wkUScript in array){
                [webView.configuration.userContentController addUserScript:wkUScript];
            }
        }
    }
    _scalesPageToFit = scalesPageToFit;
}
- (BOOL)scalesPageToFit{//设置是否根据视图大小来缩放页面
    if(_usingUIWebView){
        return [_realWebView scalesPageToFit];
    }else{
        return _scalesPageToFit;
    }
}

#pragma mark- 加载网页
- (id)loadRequest:(NSURLRequest *)request{
    self.originRequest = request;
    self.currentRequest = request;
    if(_usingUIWebView){
        [(UIWebView*)self.realWebView loadRequest:request];
        return nil;
    }else{
        return [(WKWebView*)self.realWebView loadRequest:request];
    }
}

#pragma mark- 其他
- (UIScrollView *)scrollView{//scrollView
    return [(id)self.realWebView scrollView];
}
- (NSURL *)URL{//URL
    if(_usingUIWebView){
        return [(UIWebView*)self.realWebView request].URL;;
    }else{
        return [(WKWebView*)self.realWebView URL];
    }
}
- (BOOL)isLoading{//正在加载
    return [self.realWebView isLoading];
}
- (BOOL)canGoBack{//可以返回
    
    return [self.realWebView canGoBack];
}
- (BOOL)canGoForward{//可以前进
    return [self.realWebView canGoForward];
}
- (id)goBack{//后退
    if(_usingUIWebView){
        [(UIWebView*)self.realWebView goBack];
        return nil;
    }else{
        return [(WKWebView*)self.realWebView goBack];
    }
}
- (id)goForward{//前进
    if(_usingUIWebView){
        [(UIWebView*)self.realWebView goForward];
        return nil;
    }else{
        return [(WKWebView*)self.realWebView goForward];
    }
}
- (id)reload{//刷新网页
    if(_usingUIWebView){
        [(UIWebView*)self.realWebView reload];
        return nil;
    }else{
        return [(WKWebView*)self.realWebView reload];
    }
}
- (id)reloadFromOrigin{//加载原始请求
    if(_usingUIWebView){
        if(self.originRequest){
            [self evaluateJavaScript:[NSString stringWithFormat:@"window.location.replace('%@')",self.originRequest.URL.absoluteString] completionHandler:nil];
        }
        return nil;
    }else{
        return [(WKWebView*)self.realWebView reloadFromOrigin];
    }
}
- (void)stopLoading{//停止加载
    [self.realWebView stopLoading];
}
- (id)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL{//加载HTML
    if(_usingUIWebView){
        [(UIWebView*)self.realWebView loadHTMLString:string baseURL:baseURL];
        return nil;
    }else{
        return [(WKWebView*)self.realWebView loadHTMLString:string baseURL:baseURL];
    }
}
- (NSInteger)countOfHistory{//获取当前的网页层级数
    if(_usingUIWebView){
        UIWebView* webView = self.realWebView;
        int count = [[webView stringByEvaluatingJavaScriptFromString:@"window.history.length"] intValue];
        if (count){
            return count;
        }else{
            return 1;
        }
    }else{
        WKWebView* webView = self.realWebView;
        return webView.backForwardList.backList.count;
    }
}
- (void)gobackWithStep:(NSInteger)step{//返回到第几层
    if(self.canGoBack == NO)
        return;
    if(step > 0){
        NSInteger historyCount = self.countOfHistory;
        if(step >= historyCount){
            step = historyCount - 1;
        }
        if(_usingUIWebView){
            UIWebView* webView = self.realWebView;
            [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.history.go(-%ld)", (long) step]];
        }else{
            WKWebView* webView = self.realWebView;
            WKBackForwardListItem* backItem = webView.backForwardList.backList[step];
            [webView goToBackForwardListItem:backItem];
        }
    }else{
        [self goBack];
    }
}

#pragma mark- JS相关
//添加js回调oc通知方式，适用于 iOS8 之后
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name{
    if ([_realWebView isKindOfClass:NSClassFromString(@"WKWebView")]) {
        [[(WKWebView *)_realWebView configuration].userContentController addScriptMessageHandler:scriptMessageHandler name:name];
    }
}
//注销 注册过的js回调oc通知方式，适用于 iOS8 之后
- (void)removeScriptMessageHandlerForName:(NSString *)name{
    if ([_realWebView isKindOfClass:NSClassFromString(@"WKWebView")]) {
        [[(WKWebView *)_realWebView configuration].userContentController removeScriptMessageHandlerForName:name];
    }
}
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler{
    if(_usingUIWebView){//oc调用js代码执行方法
        NSString* result = [(UIWebView*)self.realWebView stringByEvaluatingJavaScriptFromString:javaScriptString];
        if(completionHandler){
            completionHandler(result,nil);
        }
    }else{
        return [(WKWebView*)self.realWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
    }
}
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)javaScriptString{//不建议使用这个办法  因为会在内部等待webView 的执行结果
    if(_usingUIWebView){
        NSString* result = [(UIWebView*)self.realWebView stringByEvaluatingJavaScriptFromString:javaScriptString];
        return result;
    }else{
        __block NSString* result = nil;
        __block BOOL isExecuted = NO;
        [(WKWebView*)self.realWebView evaluateJavaScript:javaScriptString completionHandler:^(id obj, NSError *error) {
            result = obj;
            isExecuted = YES;
        }];
        while (isExecuted == NO) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
        return result;
    }
}

#pragma mark-  如果没有找到方法 去realWebView 中调用
- (BOOL)respondsToSelector:(SEL)aSelector{
    BOOL hasResponds = [super respondsToSelector:aSelector];
    if(hasResponds == NO){
        hasResponds = [self.delegate respondsToSelector:aSelector];
    }
    if(hasResponds == NO){
        hasResponds = [self.realWebView respondsToSelector:aSelector];
    }
    return hasResponds;
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector{
    NSMethodSignature* methodSign = [super methodSignatureForSelector:selector];
    if(methodSign == nil){
        if([self.realWebView respondsToSelector:selector]){
            methodSign = [self.realWebView methodSignatureForSelector:selector];
        }else{
            methodSign = [(id)self.delegate methodSignatureForSelector:selector];
        }
    }
    return methodSign;
}
- (void)forwardInvocation:(NSInvocation*)invocation{
    if([self.realWebView respondsToSelector:invocation.selector]){
        [invocation invokeWithTarget:self.realWebView];
    }else{
        [invocation invokeWithTarget:self.delegate];
    }
}

#pragma mark- 清理
- (void)dealloc{
    if(_usingUIWebView){
        UIWebView* webView = _realWebView;
        webView.delegate = nil;
    }else{
        WKWebView* webView = _realWebView;
        webView.UIDelegate = nil;
        webView.navigationDelegate = nil;
        [webView removeObserver:self forKeyPath:@"estimatedProgress"];
        [webView removeObserver:self forKeyPath:@"title"];
    }
    [_realWebView scrollView].delegate = nil;
    [_realWebView stopLoading];
    [(UIWebView*)_realWebView loadHTMLString:@"" baseURL:nil];
    [_realWebView stopLoading];
    [_realWebView removeFromSuperview];
    _realWebView = nil;
}

-(void)backbtnClick{
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(backBtnDelegateClick)]) {
        [self.delegate backBtnDelegateClick];
    }
}
@end
